package ruc.disorder;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.TreeMap;

public class PoissonDistribution {
    private static final int maxK = 25;
    private static final int lambda = 6; //时间间隔60s  60000

    public static TreeMap<Integer, Integer> getPoissonMap(int batchSize) {
        assert batchSize > 0;
        TreeMap<Integer, Integer> map = new TreeMap<>(); //<k,v> -> <时间差，数量> 时间差单位：10s
        int scale = 0;
        int temp = batchSize;
        while ((temp /= 10) != 0) { //数据位数
            scale++;
        }
        int round = 0;
        while (round <= maxK) {
            int v = nextPoissonStep(round, batchSize, scale);
            if (v != 0)
                map.put(round, v);
            round++;
        }
        int sum = 0;
        for (int delta : map.keySet()) {
            sum += map.get(delta);
        }

        assert !map.isEmpty();

        int last = map.lastKey();
        map.put(last, map.get(last) + batchSize - sum);
        return map;
    }

    private static int nextPoissonStep(int k, int batchSize, int scale) {

        return PoissonCalculation(lambda, k, scale)
                .multiply(BigDecimal.valueOf(batchSize)).intValue();
    }

    private static BigDecimal PoissonCalculation(int averageRateOfSuccess, int xVal, int scale) {
        return BigDecimal.valueOf(averageRateOfSuccess).pow(xVal)
                .multiply(BigDecimal.valueOf(Math.pow(Math.E, -averageRateOfSuccess)))
                .divide(factorial(BigDecimal.valueOf(xVal)), scale, RoundingMode.HALF_UP);
    }

    private static BigDecimal factorial(BigDecimal x) {
        if (x.intValue() == 1 || x.intValue() == 0) {
            return BigDecimal.valueOf(1);
        } else {
            return x.multiply(factorial(x.subtract(BigDecimal.valueOf(1))));
        }
    }

    public static void main(String[] args) {
        getPoissonMap(1000000);
        System.out.println(nextPoissonStep(1, 100, 2));
        System.out.println();
    }
}
